#pragma once

#include<iostream>
#include <sys/wait.h>
#include <sys/resource.h>

#include"../CommonComponent/Log.hpp"
#include"common.hpp"

namespace ns_run{
    class run{
    public:
        run()
        {}

        ~run()
        {}

        //传入时间单位为秒，空间为KB
        static int Run(std::string& filename,int timeLimit,int spaceLimit){
            int pid=fork();
            if(pid<0){
                Log(FATAL,"fork error\n");
                return -2;
            }
            else if(0==pid){
                //子进程
                std::string fileStdin=ns_common::fileUtility::AddInSuffix(filename).c_str();
                int fd=open(fileStdin.c_str(),O_RDONLY);
                if(fd<0)
                {
                    Log(ERROR,"can not open file\n");
                    exit(-1);
                }
                dup2(fd,0);

                std::string fileStdout=ns_common::fileUtility::AddOutSuffix(filename).c_str();
                fd=open(fileStdout.c_str(),O_WRONLY);
                if(fd<0)
                {
                    Log(ERROR,"can not open file\n");
                    exit(-1);
                }
                dup2(fd,1);

                std::string fileStderror=ns_common::fileUtility::AddRunErrSuffix(filename).c_str();
                fd=open(fileStderror.c_str(),O_WRONLY);
                if(fd<0)
                {
                    Log(ERROR,"can not open file\n");
                    exit(-1);
                }
                dup2(fd,2);

                //设置CPU时长
                struct rlimit cpu_rlimit;
                cpu_rlimit.rlim_max = RLIM_INFINITY;
                cpu_rlimit.rlim_cur = timeLimit;
                setrlimit(RLIMIT_CPU, &cpu_rlimit);

                // 设置内存大小
                struct rlimit mem_rlimit;
                mem_rlimit.rlim_max = RLIM_INFINITY;
                mem_rlimit.rlim_cur = spaceLimit * 1024; 
                setrlimit(RLIMIT_AS, &mem_rlimit);

                std::string exefile=ns_common::fileUtility::AddExeSuffix(filename);
                execlp(exefile.c_str(),exefile.c_str(),NULL);

                //执行到这里说明程序替换出错
                Log(ERROR,"execlp error\n");
                exit(-1);
            }
            else{
                //父进程
                int status=0;
                waitpid(pid,&status,0);
                //只要用户的代码运行成功，无论对错，就应该将每一个测试用例的运行结果写入到标准输出中，对错由上层判断
                if(WIFEXITED(status)){
                    if(ns_common::fileUtility::IsFileEmpty(ns_common::fileUtility::AddRunErrSuffix(filename))){
                        Log(INFO,"run successfully\n");
                        return 0;
                    }
                    return -2;
                }

                //此时子进程一定是因为某些错误被信号终止
                Log(INFO,"run error\n");
                return WTERMSIG(status); // 获取导致子进程终止的信号
            } 
        }
    };
}